package day03;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {
    public static void main(String[] args) throws IOException {
        NioServer server = new NioServer();
        server.start();
    }
    public void start() throws IOException {
        int port = 8888;
        //创建 服务器端 ServerSocketChannel 对象
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //绑定 服务器端口
        serverSocketChannel.bind(new InetSocketAddress(port));
        //设置非阻塞式工作模式
        serverSocketChannel.configureBlocking(false);
        //创建一个处理用户请求的 selector 对象
        try (Selector selector = Selector.open()){
            //将Selector注册到serverSocketChannel，等待用户的请求
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            //selector.select()>0 表示用户开始请求了或者是发送了数据
            // selector.select() 是阻塞式方法，用户请求时候才继续执行
            while (selector.select()>0){
                // keys() 全部注册的key是只读的key
                //selectedKeys() 返回的是用户请求的事件
                Set<SelectionKey> keys = selector.selectedKeys();
                //keys 包含各种用户请求的情况
                Iterator<SelectionKey> iterator = keys.iterator();
                while (iterator.hasNext()){
                    //获取用的请求状态 key
                    SelectionKey key = iterator.next();
                    //key.isAcceptable() 表示收到的请求是用户连接请求
                    if (key.isAcceptable()){
                        System.out.println("收到用户的连接请求");
                        //SocketChannel 用于处理用用户请求的通道
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        //将socketChannel设置为非阻塞工作模式
                        socketChannel.configureBlocking(false);
                        //在 selector 注册，接收用户的后续请求，将请求信息存储到 ByteBuffer 中
                        // ByteBuffer.allocate(1024) 创建一个 1024 字节的缓冲区
                        socketChannel.register(selector,
                                SelectionKey.OP_READ, ByteBuffer.allocate(1024));

                    }else if (key.isReadable()){
                        // key.isReadable() 返回 true 表示用户发送了数据
                        // 获取接收用户数据的通道 socketChannel
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        // 从 key 中得到数据缓存
                        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                        //从 socketChannel 读取数据，然后对byteBuffer 进行解码
                        while ((socketChannel.read(byteBuffer))!=-1){
                            byteBuffer.flip();
                            String str = new String(byteBuffer.array(), 0, byteBuffer.limit());
                            System.out.println(str);
                            byteBuffer.clear();
                        }
                    }
                    //将处理完的key删除，避免重复处理
                    iterator.remove();
                    //System.out.println(iterator.getClass());
                }
            }
        }
    }
}
